package com.virgo.redis.aspectj;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.virgo.common.exception.IApplicationException;
import com.virgo.redis.annotation.ICache;
import com.virgo.redis.service.CacheService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;

@Aspect
@Component
public class ICacheAspect {

	@Autowired
	private CacheService cacheService;

	@Around("@annotation(iCache)")
	public Object doCache(ProceedingJoinPoint joinPoint, ICache iCache) {
		Object result;
		try
		{
			//1 获得重载后的方法名
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			Method method = signature.getMethod();

			//2 确定方法名后获得该方法上面配置的注解标签MyRedisCache
			ICache ICacheAnnotation = method.getAnnotation(ICache.class);

			//3 拿到了MyRedisCache这个注解标签，获得该注解上面配置的参数进行封装和调用
			String keyPrefix = ICacheAnnotation.keyPrefix();
			String matchValueSpringEL = ICacheAnnotation.matchValue();

			//4 SpringEL 解析器
			ExpressionParser parser = new SpelExpressionParser();
			Expression expression = parser.parseExpression(matchValueSpringEL);//#id
			EvaluationContext context = new StandardEvaluationContext();

			//5 获得方法里面的形参个数
			Object[] args = joinPoint.getArgs();
			DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
			String[] parameterNames = discoverer.getParameterNames(method);
			String key = keyPrefix;
			if (!ObjectUtils.isEmpty(parameterNames)) {
				for (int i = 0; i < parameterNames.length; i++)
				{
					context.setVariable(parameterNames[i], args[i].toString());
				}
				Object expressionValue = expression.getValue(context);
				if (!ObjectUtils.isEmpty(expressionValue)) {
					key = keyPrefix + "_" + expressionValue;
				}
			}

			//7 先去redis里面查询看有没有
			String cacheResult = cacheService.get(key);
			if (!ObjectUtils.isEmpty(cacheResult)) {
				return JSON.parse(cacheResult);
			}

			//8 redis里面没有，去业务查询
			result = joinPoint.proceed();
			if (!ObjectUtils.isEmpty(result)) {
				cacheResult = JSON.toJSONString(result);
				int ttlTime = ICacheAnnotation.ttl();
				if (ttlTime == 0) {
					int ttlMin = ICacheAnnotation.ttlMin();
					int ttlMax = ICacheAnnotation.ttlMax();
					if (ttlMin != 0 && ttlMax != 0) {
						ttlTime = RandomUtil.randomInt(ttlMin,ttlMax);
						cacheService.set(key,cacheResult,ttlTime);
					} else {
						cacheService.set(key,cacheResult);
					}
				} else {
					cacheService.set(key,cacheResult,ttlTime);
				}
			}
		} catch (Throwable throwable) {
			throw new IApplicationException("请重试");
		}
		return result;
	}
}